import 'package:vm_service/vm_service.dart';

import '../leak/model/leak_node.dart';
import '../leak/parse_leak.dart';
import '../leak_stream_watcher.dart';
import '../utils/log_util.dart';
import '../utils/object_util.dart';

class LeakTask {
  Expando? expando;

  LeakTask(this.expando);

  Future<List<LeakNode>?> start({String? tag}) async {
    List<LeakNode>? leakNodes;
    if (expando == null) {
      LogUtil.d('没有检测到泄露');
      return leakNodes;
    }

    await gc();

    var weakPropertyKeys = await getWeakKeyRefs(expando!);

    if (weakPropertyKeys.isEmpty) {
      expando = null;
      LogUtil.d('没有检测到泄露');
      return null;
    }
    expando = null;

    await gc();

    for (int i = 0; i < weakPropertyKeys.length; i++) {
      InstanceRef instanceRef = weakPropertyKeys[i];
      if (instanceRef.id == 'objects/null') {
        // LogUtil.d('checkLeak instanceRef = $instanceRef');
        break;
      }

      RetainingPath retainingPath = await getRetainingPath(instanceRef.id!);
      LeakNode? _leakInfoHead;
      LeakNode? pre;
      bool isBreak = false;
      for (var i = 0; i < retainingPath.elements!.length; i++) {
        RetainingObject p = retainingPath.elements![i];

        LeakNode current = LeakNode();
        current.parentField = p.parentField;
        bool skip =
            await parsers[p.value!.runtimeType]?.paresRefSkip(p.value!, p.parentField, current) ??
                true;

        if (skip) {
          isBreak = true;
          break;
        }

        if (_leakInfoHead == null) {
          _leakInfoHead = current;
          pre = _leakInfoHead;
        } else {
          pre?.next = current;
          pre = current;
        }
      }

      if (isBreak) {
        break;
      }

      if (_leakInfoHead != null) {
        leakNodes?.add(_leakInfoHead);
        LeakStream.getInstance().addLeakNode(_leakInfoHead);
      }
    }

    if (null == leakNodes || leakNodes.isEmpty) {
      LogUtil.d('没有检测到泄露');
    }
    return leakNodes;
  }
}
